package net.brokenroad.gamma.tools;

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;

import net.brokenroad.gamma.net.*;
import net.brokenroad.gamma.net.Packet;
import net.brokenroad.gamma.gui.*;

public class PacketTester implements ActionListener
{
	JMenuBar menuBar;
	JMenu menu;
	JMenuItem connect;
	JFrame frame;
	JButton sendButton;
	JComboBox packetType;
	JTextField string1, string2, int1, int2, int3, int4, int5;
	JTextArea results;
	JPanel[] rows;
	Socket socket = null;
	ObjectInputStream in;
	ObjectOutputStream out;
	PacketHistoryFrame phf;
	SessionConnectFrame scf;
	Packet toSend, reply;
	ArrayList<Packet> sent, received;

	public static void main(String[] args)
	{
		new PacketTester();
	}

	public PacketTester()
	{
		sent = new ArrayList<Packet>(1);
		received = new ArrayList<Packet>(1);
		phf = new PacketHistoryFrame();

		frame = new JFrame("Gamma Packet Tester");
		frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.PAGE_AXIS));

		menuBar = new JMenuBar();
		menu = new JMenu("Connection");
		menuBar.add(menu);
		frame.setJMenuBar(menuBar);

		connect = new JMenuItem("Connect");
		connect.addActionListener(this);
		menu.add(connect);

		rows = new JPanel[5];
		for (int i = 0; i < 5; i++)
		{
			rows[i] = new JPanel();
			rows[i].setLayout(new BoxLayout(rows[i], BoxLayout.LINE_AXIS));
		}

		sendButton = new JButton("Send Packet");
		sendButton.addActionListener(this);

		String[] options =
		{"Authorization (AUTH)", "Version Info (VERSION)", "Success (SUCCESS)",
		    "Failure (FAILURE)", "Resource List (LIST)",
		    "Info Request (REQUEST_INFO)", "Join (JOIN)",
		    "Provide Details (DETAILS)", "Document Change (CHANGE)", "Quit (QUIT)"};
		packetType = new JComboBox(options);

		string1 = new JTextField();
		string2 = new JTextField();
		int1 = new JTextField("0");
		int2 = new JTextField("0");
		int3 = new JTextField("0");
		int4 = new JTextField("0");
		int5 = new JTextField("0");
		results = new JTextArea();

		rows[0].add(new JLabel("Packet Type:"));
		rows[0].add(packetType);
		rows[1].add(new JLabel("String1 field:"));
		rows[1].add(string1);
		rows[2].add(new JLabel("String2 field:"));
		rows[2].add(string2);
		rows[3].add(int1);
		rows[3].add(int2);
		rows[3].add(int3);
		rows[3].add(int4);
		rows[3].add(int5);
		rows[4].add(new JLabel("0"));
		rows[4].add(new JLabel("1"));
		rows[4].add(new JLabel("2"));
		rows[4].add(new JLabel("3"));
		rows[4].add(new JLabel("4"));

		frame.add(rows[0]);
		frame.add(rows[1]);
		frame.add(rows[2]);
		frame.add(new JLabel("Int fields:"));
		frame.add(rows[3]);
		frame.add(rows[4]);
		frame.add(sendButton);

		frame.setSize(300, 250);
		
		frame.setLocation(Toolkit.getDefaultToolkit().getScreenSize().width - 450, 50);

		frame.setVisible(true);
	}

	public void actionPerformed(ActionEvent ae)
	{
		if (ae.getSource() == connect)
			// init connection
			scf = new SessionConnectFrame(this);
		else if (ae.getSource() == sendButton)
		{
			if (socket == null)
			{
				JOptionPane.showMessageDialog(frame,
				    "Can't send packets without establishing a connection!", "Error",
				    JOptionPane.ERROR_MESSAGE);
				return;
			}
			results.setText("");
			toSend = new Packet(Enum.valueOf(Packet.PacketType.class,
			    ((String) packetType.getSelectedItem()).substring(
			        ((String) packetType.getSelectedItem()).lastIndexOf('(') + 1,
			        ((String) packetType.getSelectedItem()).lastIndexOf(')'))),
			    string1.getText(), string2.getText(), Integer
			        .parseInt(int1.getText()), Integer.parseInt(int2.getText()),
			    Integer.parseInt(int3.getText()), Integer.parseInt(int4.getText()),
			    Integer.parseInt(int5.getText()));
			results.append("Sending packet: " + toSend);
			try
			{
				out.writeObject(toSend);
				out.flush();
				reply = (Packet) in.readObject();
				results.append("Received packet: " + reply);
			} catch (ClassNotFoundException cnfe)
			{
				results
				    .setText("Your packet tester is broken in a fundamental way. Please reinstall.");
			} catch (Exception e)
			{
				results.setText(e.getMessage() + "\n\n" + e.getStackTrace());
			}
			phf.updateHistory(toSend, reply);
		} else if (ae.getSource() == scf.accept)
		{
			ConnectionInfo ci = scf.getCInfo();
			try
			{
				socket = new Socket(ci.getHostname(), ci.getPort());
				if (!socket.isConnected())
					throw new IOException();
				out = new ObjectOutputStream(new BufferedOutputStream(socket
				    .getOutputStream()));
				out.flush();
				in = new ObjectInputStream(new BufferedInputStream(socket
				    .getInputStream()));
				scf.close();
			} catch (IOException e)
			{
				System.err.println("Sorry, you misspelled the hostname!");
			}
		}
	}
}

class PacketHistoryFrame extends JFrame implements ListSelectionListener
{
	private static final long serialVersionUID = 1L;

	ArrayList<Packet> sent, received;

	JTable packetTable;

	JScrollPane scrollPane;

	JEditorPane sentDisplay, receivedDisplay;

	JPanel displays;

	DefaultTableModel model;

	public PacketHistoryFrame()
	{
		super("Packet History");
		sent = new ArrayList<Packet>(1);
		received = new ArrayList<Packet>(1);

		setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));

		model = new DefaultTableModel();
		packetTable = new JTable(model)
		{
			private static final long serialVersionUID = 1L;

			public boolean isCellEditable(int row, int col)
			{
				return false;
			}

			public Component prepareRenderer(TableCellRenderer renderer,
			    int rowIndex, int vColIndex)
			{
				Component c = super.prepareRenderer(renderer, rowIndex, vColIndex);
				if (rowIndex % 2 == 0 && !isCellSelected(rowIndex, vColIndex))
					c.setBackground(new Color(236, 243, 254));
				else
					// If not shaded, match the table's background
					c.setBackground(getBackground());
				if (isCellSelected(rowIndex, vColIndex))
					c.setBackground(new Color(181, 213, 255));
				return c;
			}
		};
		packetTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		packetTable.getSelectionModel().addListSelectionListener(this);
		model.addColumn("#");
		model.addColumn("Sent");
		model.addColumn("Received");
		packetTable.getColumn("#").setMinWidth(20);
		packetTable.getColumn("#").setMaxWidth(40);

		scrollPane = new JScrollPane(packetTable);
		packetTable.setPreferredScrollableViewportSize(new Dimension(500, 350));
		scrollPane.setPreferredSize(new Dimension(500, 350));
		add(scrollPane);

		displays = new JPanel();
		displays.setLayout(new BoxLayout(displays, BoxLayout.LINE_AXIS));

		sentDisplay = new JEditorPane("text/html",
		    "<html><body><b>Sent packet info.</b></body></html>");
		sentDisplay.setEditable(false);
		sentDisplay.setPreferredSize(new Dimension(245, 130));
		displays.add(sentDisplay);

		displays.add(Box.createRigidArea(new Dimension(10, 130)));

		receivedDisplay = new JEditorPane("text/html",
		    "<html><body><b>Received packet info.</b></body></html>");
		receivedDisplay.setEditable(false);
		receivedDisplay.setPreferredSize(new Dimension(245, 130));
		displays.add(receivedDisplay);

		add(displays);

		setSize(500, 480);
		setLocation(Toolkit.getDefaultToolkit().getScreenSize().width - 550, 350);
		setVisible(true);
	}

	public void updateHistory(Packet sent, Packet received)
	{
		this.sent.add(sent);
		this.received.add(received);
		model.addRow(new Object[]
		{Integer.valueOf(model.getRowCount()), sent, received});
	}

	public void valueChanged(ListSelectionEvent e)
	{
		// Ignore extra messages, wait for the last.
		if (e.getValueIsAdjusting())
			return;

		ListSelectionModel lsm = (ListSelectionModel) e.getSource();
		if (lsm.isSelectionEmpty())
		{

			sentDisplay.setText("<html><body><b>Sent packet info.</b></body></html>");
			receivedDisplay
			    .setText("<html><body><b>Received packet info.</b></body></html>");
		} else
		{
			int selectedRow = lsm.getMinSelectionIndex();
			Packet sentPacket = sent.get(selectedRow);
			Packet receivedPacket = received.get(selectedRow);
			sentDisplay.setText("<html><body>" + sentPacket.toHTML()
			    + "</body></html>");
			receivedDisplay.setText("<html><body>" + receivedPacket.toHTML()
			    + "</body></html>");
		}
	}
}
